package com.zh.business.service.web.common.impl;

import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.zh.business.service.web.common.TokenService;
import com.zh.zhbootcommon.common.BasicConstants;
import com.zh.zhbootcommon.common.RedisKey;
import com.zh.zhbootcommon.common.result.impl.ResultCode;
import com.zh.zhbootcommon.config.exception.ZhBootException;
import com.zh.zhbootcommon.entity.user.User;
import com.zh.zhbootcommon.utils.common.RedisUtils;
import com.zh.business.util.CommonUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.security.MessageDigest;
import java.util.*;

/**
 * 描述: Token
 *
 * @author: yanglin
 * @Date: 2021-08-31-9:00
 * @Version: 1.0
 */
@Slf4j
@Service
public class TokenServiceImpl implements TokenService {

    @Autowired
    RedisUtils redisUtils;

    @Override
    public String createJwtToken(User user) {
        String token = "";
        token = JWT.create().withAudience(StrUtil.toString(user.getUserId()))
                .sign(Algorithm.HMAC256(user.getUserPassword()));
        return token;
    }

    @Override
    public String createToken() {
        String str = RandomUtil.randomUUID();
        StrBuilder token = new StrBuilder();
        try {
            token.append(RedisKey.MP_TOKEN.getValue()).append(str);
            redisUtils.set(token.toString(), token.toString(), CommonUtils.MP_TOKEN_EXPIRE);
            boolean notEmpty = StrUtil.isNotEmpty(token.toString());
            if (notEmpty) {
                return token.toString();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    @SneakyThrows
    @Override
    public String createToken(HttpServletRequest request) {
        Map<String, String> data = new HashMap<String, String>();
        // 所有请求参数
        Enumeration<String> params = request.getParameterNames();
        while (params.hasMoreElements()) {
            String paramName = params.nextElement();
            String[] paramValues = request.getParameterValues(paramName);
            if (paramValues.length == 1) {
                String paramValue = paramValues[0];
                if (paramValue.length() != 0) {
                    data.put(paramName, paramValue);
                }
            }
        }
        // 生成签名
        Set<String> keySet = data.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            // 参数值为空，则不参与签名
            if (data.get(k).trim().length() > 0) {
                sb.append(k).append("=").append(data.get(k).trim()).append("&");
            }
        }
        String md5Str = sb.toString();
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(md5Str.getBytes("UTF-8"));
        sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }

    @Override
    public boolean checkToken(HttpServletRequest request) {
        String token = request.getHeader(BasicConstants.MP_TOKEN);
        if (StrUtil.isBlank(token)) {
            // header中不存在token
            token = request.getParameter(BasicConstants.MP_TOKEN);
            if (StrUtil.isBlank(token)) {
                // parameter中也不存在token
                throw new ZhBootException(ResultCode.PARAM_IS_NULL.getCode(), ResultCode.PARAM_IS_NULL.getMsg());
            }
        }
        if (!redisUtils.hasKey(token)) {
            throw new ZhBootException(ResultCode.REPETITIVE_OPERATION.getCode(), ResultCode.REPETITIVE_OPERATION.getMsg());
        }

        boolean remove = redisUtils.del(token);
        if (!remove) {
            throw new ZhBootException(ResultCode.TOKEN_INVALID.getCode(), ResultCode.TOKEN_INVALID.getMsg());
        }
        // log.info("验证Token->, {}, 通过", token);
        return true;
    }
}
